# coding:utf-8
import io
import json
import os
import random
import traceback
from datetime import datetime
from time import time, sleep
import jieba
import requests
from flask import jsonify, request, current_app, g, send_file
from sqlalchemy import or_

from app import redisclient, redisclientRemote
from app.libs.ParseArticles import ParseArticle
from app.libs.ParseDocument import ParseDocument
from app.libs.ParseDocumentHtml import ParseDocumentHtml
from app.libs.aigc_tools import PasreArticle
from app.libs.createLocalIndex import CreatLocalIndex, CreatLocalIndexRemote
from app.libs.error_code import Success
from app.libs.poster import PosterGenerator
from app.libs.qrcode import gzh_qrcode
from app.libs.redprint import Redprint
from app.models.ai_sentence import AISentence
from app.libs.token_auth import auth
from app.models.aigc_content import aigc_content
from app.models.aigc_order_info import aigc_order_info
from app.models.aigc_paragraphs import AigcParagraphs
from app.models.captcha import captcha
from app.models.document_dom import DocumentDom
from app.models.report_info import report_info
from app.models.sentences_word import SentenceWord
from app.models.taobao_orders import taobao_orders
from app.models.base import db
from app.models.order_info import order_info
from app.models.orders import orders
from app.models.paragraphs import Paragraphs
from app.models.sentence import sentence
from app.models.writer_orders import writer_orders
from app.validators.article import AIGCRewriteForm, ArticleSubmitForm, ShopForm, DocUploadForm, DeleteReportForm, \
    WriterOrderNumber, WriterArticleSubmitForm, WriterReportSearchForm, ReArticleSubmitForm, ArticleBatchSubmitForm, \
    MutilDocUploadForm, AIRewriteForm, UnitForm, DocUploadFormWeb, MyReportSearchForm, ReportSearchForm, VerifyForm, \
    ReportSearchPageForm
from app.view_models.OrderInfo import OrderInfolistView, OrderInfolistByTokenView, OrderInfolistByPageView
from app.libs.tools import cut_sentences, get_key_words, parseDocument, check_paragrpah
from app.config.setting import *
from app import executor
from app.config.secure import SELFDOC_PATH, InsertDocUrl
from app.libs.ai_tools import call_with_messages
from app.view_models.WxReportInfo import WxReportInfoListView

api = Redprint('article')



@api.route("/submit_test", methods=['POST'])
def submit_test():
    form = ArticleSubmitForm().validate_for_api()
    current_time = str(round(time() * 1000))
    if form.file_path.data != '':
        if form.uid.data != 0:
            order_number = f'88{current_time}'
        else:
            order_number = f'8{current_time}'
    else:
        if form.uid.data != 0:
            order_number = f'99{current_time}'
        else:
            order_number = f'9{current_time}'
    with db.auto_commit():
        order = orders()
        order.order_number = order_number
        order.content = form.content.data
        order.author = form.author.data
        order.char_sum = form.chars_sum.data
        order.title = form.title.data
        db.session.add(order)
        if form.uid.data != 0:
            report_info_model = report_info()
            report_info_model.order_number = order_number
            report_info_model.title = form.title.data
            report_info_model.author = form.author.data
            report_info_model.chars_sum = form.chars_sum.data
            report_info_model.user = form.uid.data
            db.session.add(report_info_model)
        for taobao_order in form.taobao_orders:
            info = order_info()
            info.taobao_orders = taobao_order
            info.order_number = order_number
            info.title = form.title.data
            info.chars_sum = form.chars_sum.data
            info.author = form.author.data
            info.file_path = form.file_path.data
            info.user = form.uid.data
            db.session.add(info)

    if form.file_path.data != '':
        executor.submit(__db_document_operation, form.file_path.data, order_number, form.selffileList.data,
                        form.checkmodel.data, current_app._get_current_object())
    else:
        executor.submit(__db_operation, order_number, form.content.data,
                        form.selffileList.data, form.checkmodel.data,
                        current_app._get_current_object())
    return Success()


@api.route("/submit", methods=['POST'])
def submit():
    form = ArticleSubmitForm().validate_for_api()
    current_time = str(round(time() * 1000))
    if form.file_path.data != '':
        if form.uid.data != 0:
            order_number = f'88{current_time}'
        else:
            order_number = f'8{current_time}'
    else:
        if form.uid.data != 0:
            order_number = f'99{current_time}'
        else:
            order_number = f'9{current_time}'
    with db.auto_commit():
        order = orders()
        order.order_number = order_number
        order.content = form.content.data
        order.author = form.author.data
        order.char_sum = form.chars_sum.data
        order.title = form.title.data
        db.session.add(order)
        if form.uid.data != 0:
            report_info_model = report_info()
            report_info_model.order_number = order_number
            report_info_model.title = form.title.data
            report_info_model.author = form.author.data
            report_info_model.chars_sum = form.chars_sum.data
            report_info_model.user = form.uid.data
            db.session.add(report_info_model)
        for taobao_order in form.taobao_orders:
            info = order_info()
            info.taobao_orders = taobao_order
            info.order_number = order_number
            info.title = form.title.data
            info.chars_sum = form.chars_sum.data
            info.author = form.author.data
            info.file_path = form.file_path.data
            info.user = form.uid.data
            db.session.add(info)
    unfinished = order_info.query.filter_by(taobao_orders=form.order_number.data).filter_by(completed=0).all()
    if len(unfinished) > 3:
        queue = 'low'
    else:
        queue = 'high'
    if form.file_path.data != '':
        executor.submit(__db_document_operation, form.file_path.data, order_number, form.selffileList.data,
                        form.checkmodel.data, queue,current_app._get_current_object())
    else:
        executor.submit(__db_operation, order_number, form.content.data,
                        form.selffileList.data, form.checkmodel.data,queue,
                        current_app._get_current_object())
    if form.check_aigc.data == 1:
        # __submit_aigc()
        executor.submit(__submit_aigc, order_number, form.content.data,form.author.data, form.chars_sum.data,form.title.data,form.taobao_orders,current_app._get_current_object())
    return Success()

def __submit_aigc(order_number, content, author, chars_sum, title,taobao_orders,app):
    with app.app_context():
        with db.auto_commit():
            aigc_content_model = aigc_content()
            aigc_content_model.order_number = order_number
            aigc_content_model.content = content
            aigc_content_model.author = author
            aigc_content_model.char_sum = chars_sum
            aigc_content_model.title = title
            db.session.add(aigc_content_model)
            for taobao_order in taobao_orders:
                info = aigc_order_info()
                info.taobao_orders = taobao_order
                info.order_number = order_number
                info.title = title
                info.chars_sum = chars_sum
                info.author = author
                info.file_path = ''
                info.user = 0
                db.session.add(info)
        parseModel = PasreArticle(content)
        article_fragments = parseModel.run()
        with db.auto_commit():
            for fragment in article_fragments:
                if fragment['content'].strip() != '':
                    paragraphModel = AigcParagraphs()
                    paragraphModel.order_number = order_number
                    paragraphModel.paragraph_index = fragment['paragraph_index']
                    paragraphModel.content = fragment['content'].strip()
                    paragraphModel.type = fragment['type']
                    db.session.add(paragraphModel)
        target_redisclient = redisclientRemote
        target_redisclient.push_task(AIGC_TASK, order_number)

@api.route('/getmpqrcode', methods=["GET"])
def getMpQRCode():
    order_number = request.args.get('order_number')
    qr_model = gzh_qrcode()
    img = qr_model.mp_qrcode(f'unlock_ai##{order_number}')
    return send_file(
        io.BytesIO(img),
        mimetype='image/jpeg',
        as_attachment=False,
        attachment_filename='image.jpg'
    )


@api.route('/ai_rewrite', methods=["POST"])
def ai_rewrite():
    form = AIRewriteForm().validate_for_api()
    count = AISentence.query.filter_by(order_number=form.order_number.data).count()
    info = order_info.query.filter_by(order_number=form.order_number.data).first()
    if count > 10 and info.ai_lock == 1:
        if form.order_number.data[0:2] in ['88', '99']:
            return jsonify({
                'error_code': 2,
                'data': {
                    'img': 'img'
                },
                'message': '分享小程序给朋友，解锁该报告智能改写'
            })
        else:
            qr_model = gzh_qrcode()
            ticket = qr_model.unlock_ai_qrcode_ticket(form.order_number.data)
            return jsonify({
                'error_code': 1,
                'data': {
                    'ticket': ticket
                },
                'message': '关注公众号，解锁该报告智能改写'
            })
    ai_sentences = AISentence.query.filter_by(order_number=form.order_number.data).filter_by(
        sentence_index=form.sentence_index.data).all()
    if len(ai_sentences) > 3:
        current_ai_sentence = '1' if form.current_ai_sentence.data == '' else form.current_ai_sentence.data
        ai_sentence = AISentence.query.filter_by(order_number=form.order_number.data).filter_by(
            sentence_index=form.sentence_index.data).filter(AISentence.ai_sentence != current_ai_sentence).all()
        if len(ai_sentence) > 0:
            selected_ai_sentence = random.choice(ai_sentence).ai_sentence
        else:
            selected_ai_sentence = current_ai_sentence
        print(selected_ai_sentence)
        return jsonify({
            'error_code': 0,
            'data': {
                'anwser': selected_ai_sentence
            },
            'message': 'ok'
        })
    elif len(ai_sentences) > 0 and form.current_ai_sentence.data == '':
        selected_ai_sentence = random.choice(ai_sentences)
        return jsonify({
            'error_code': 0,
            'data': {
                'anwser': selected_ai_sentence.ai_sentence
            },
            'message': 'ok'
        })
    anwser = call_with_messages(form.sentence.data)
    if anwser != '':
        with db.auto_commit():
            ai_sentence = AISentence()
            ai_sentence.order_number = form.order_number.data
            ai_sentence.sentence_index = form.sentence_index.data
            ai_sentence.origin_sentence = form.sentence.data
            ai_sentence.ai_sentence = anwser
            db.session.add(ai_sentence)
        return jsonify({
            'error_code': 0,
            'data': {
                'anwser': anwser
            },
            'message': 'ok'
        })
    else:
        return jsonify({
            'error_code': 1000,
            'message': '出错了，请重试！'
        })

@api.route('/aigc_rewrite', methods=['POST'])
def aigc_rewrite():
    form = AIGCRewriteForm().validate_for_api()
    anwser = call_with_messages(form.sentence.data)
    if anwser != '':
        return jsonify({
            'error_code': 0,
            'data': {
                'anwser': anwser
            },
            'message': 'ok'
        })
    else:
        return jsonify({
            'error_code': 1000,
            'message': '出错了，请重试！'
        })


@api.route("/resubmit", methods=['POST'])
def repeart_submit():
    form = ReArticleSubmitForm().validate_for_api()
    order_number = form.order_number.data
    if order_number[0] == '8':
        sentences = SentenceWord.query.filter_by(check=1).filter_by(order_number=order_number).all()
        for item in sentences:
            if len(item.content.strip()) > 9:
                str_words_list = jieba.lcut(item.content)
                str_words = []
                for words in str_words_list:
                    if len(words) >= 2:
                        str_words.append(words)
                strwords = '**'.join(str_words)
                redis_data = order_number + "&&" + str(item.sentence_index) + "&&" + item.content + '&&' + strwords
                redisclient.client.lpush(order_number, redis_data)
                redisclient.client.lpush(f'polymerize_{order_number}', redis_data)
    redisclient.client.lpush('local_task', order_number)
    redisclient.client.lpush(POLYMERIZE_TASK, order_number)
    return Success()


@api.route('/upload', methods=['POST'])
def upload():
    form = DocUploadFormWeb().validate_for_api()
    res = {
        'content': form.content.data,
        'file_path': form.filePath.data,
        'char_sum': form.char_sum.data,
        'error_code': 0
    }
    return jsonify(res)


@api.route('/mutiupload', methods=['POST'])
def self_upload():
    form = MutilDocUploadForm().validate_for_api()
    res = {
        'file_path': form.filePath.data,
        'file_name': form.filename.data,
        'uid': form.filename.data,
        'error_code': 0
    }
    return jsonify(res)


@api.route('/search', methods=['POST'])
def search():
    form = ReportSearchForm().validate_for_api()
    view = OrderInfolistView()
    res = order_info.query.filter_by(taobao_orders=form.order_number.data).order_by(
        order_info.create_time.desc()).all()
    taobaoinfo = taobao_orders.query.filter_by(order_number=form.order_number.data).first()
    remain = taobaoinfo.text_check_remain+taobaoinfo.text_check_unlimit_remain if taobaoinfo else 0
    view.fill(res, remain)
    return jsonify(view)


@api.route('/search_page', methods=['POST'])
def searchByPage():
    form = ReportSearchPageForm().validate_for_api()
    view = OrderInfolistByPageView()
    reports = order_info.query.filter_by(taobao_orders=form.order_number.data).order_by(
        order_info.create_time.desc()).paginate(
        form.page.data,
        form.limit.data,
        error_out=False)
    taobaoinfo = taobao_orders.query.filter_by(order_number=form.order_number.data).first()
    remain = taobaoinfo.text_check_remain+taobaoinfo.text_check_unlimit_remain if taobaoinfo else 0
    view.fill(reports, remain)
    return jsonify(view)


@api.route('/search_by_user', methods=['POST'])
@auth.login_required
def searchByUser():
    form = MyReportSearchForm(g).validate_for_api()
    view = OrderInfolistByTokenView()
    reports = order_info.query.filter_by(user=g.user.uid).order_by(order_info.create_time.desc()).paginate(
        form.page.data,
        form.limit.data,
        error_out=False)
    view.fill(reports)
    return jsonify(view)


@api.route('/writer_search', methods=['POST'])
def writer_search():
    form = WriterReportSearchForm().validate_for_api()
    view = OrderInfolistView()
    res = order_info.query.filter_by(taobao_orders=form.order_number.data).order_by(
        order_info.create_time.desc()).all()
    writer_orders_info = writer_orders.query.filter_by(order_number=form.order_number.data).first()
    remain = writer_orders_info.num if writer_orders_info else 0
    view.fill(res, remain)
    return jsonify(view)


@api.route('/delete', methods=['POST'])
def delete():
    form = DeleteReportForm().validate_for_api()
    with db.auto_commit():
        order_info.query.filter_by(order_number=form.order_number.data).update({
            'is_delete': 1
        })
    return Success()


@api.route('/shop', methods=['POST'])
def shop():
    form = ShopForm().validate_for_api()
    url = redisclient.getshop(form.domain.data)
    return jsonify({'shop': url})


@api.route('/unit', methods=['POST'])
def unit():
    form = UnitForm().validate_for_api()
    unit = redisclient.getunit(form.domain.data)
    return jsonify({'unit': unit})


@api.route('/checkreport', methods=['GET'])
def check():
    order_number = request.args['orname']
    report = captcha.query.filter(captcha.captcha_number == order_number).first()
    if report:
        res = {
            'msg': 0,

            'title': report.title,
            'yz': report.captcha_number,
            'zx': report.char_sum,
            'pe': report.similar_rate,
            'date': report.create_time
        }
    else:
        res = {
            'msg': 1
        }
    return jsonify(res)


@api.route('/verifyreport', methods=['POST'])
def verify():
    form = VerifyForm().validate_for_api()
    report = captcha.query.filter(captcha.captcha_number == form.captcha.data).first()
    if report:
        res = {
            'error_code': 0,
            'title': report.title,
            'captcha': report.captcha_number,
            'char_sum': report.char_sum,
            'similar_rate': report.similar_rate,
            'create_date': report.create_time
        }
    else:
        res = {
            'error_code': 1001,
            'msg': '不存在该报告！'
        }
    return jsonify(res)


@api.route('/checkauth', methods=['GET'])
def checkauth():
    name = request.args['orname']
    info = auth.query.filter(or_(auth.company == name, auth.shop == name)).first()
    if info:
        res = {
            'msg': 0,
            'auth': info.auth,
            'company': info.company,
            'shop': info.shop,
            'expire': info.expire
        }
    else:
        res = {
            'msg': 1
        }
    return jsonify(res)


@api.route("/writer_submit", methods=['POST'])
def writer_submit():
    form = WriterArticleSubmitForm().validate_for_api()
    sentences, paragraph_content = cut_sentences(form.content.data)
    chars_sum = 0
    for item in sentences:
        if item['check'] == 1:
            chars_sum += len(item['content'])
    with db.auto_commit():
        current_time = str(round(time() * 1000))
        order_number = '9' + current_time
        order = orders()
        order.order_number = order_number
        order.content = form.content.data
        order.author = form.author.data
        order.char_sum = chars_sum
        order.title = form.title.data
        db.session.add(order)

        info = order_info()
        info.taobao_orders = form.order_number.data
        info.order_number = order_number
        info.title = form.title.data
        info.chars_sum = chars_sum
        info.author = form.author.data
        db.session.add(info)

        executor.submit(__writer_db_operation, order_number, form.content.data,
                        current_app._get_current_object())

        return Success()


@api.route('/create_writer_order', methods=['POST'])
def create_writer_order_number():
    form = WriterOrderNumber().validate_for_api()
    info = writer_orders.query.filter_by(order_number=form.order_number.data).first()
    with db.auto_commit():
        if not info:
            writer_orders_model = writer_orders()
            writer_orders_model.order_number = form.order_number.data
            writer_orders_model.num = form.num.data
            db.session.add(writer_orders_model)
        else:
            writer_orders.query.filter_by(order_number=form.order_number.data).update({
                "num": info.num + 2
            })
    return Success()


def __db_operation(order_number, content, selffileList, checkmodel,queue, app):
    with app.app_context():
        with db.auto_commit():

            parseModel = ParseArticle(content)
            parseModel.cut()
            paragraph_model = Paragraphs()
            sentence_model = sentence()
            target_redisclient = redisclientRemote
            paragraph_model.insert_paragrahs(parseModel.paragraph_content, order_number)
            sentence_model.insert_sentences(parseModel.contents, order_number)

            check_sentences = sentence.query.filter_by(order_number=order_number).filter_by(check=1).order_by(
                sentence.check_id).all()
            target_redisclient.setCheckData(check_sentences, 2, [])
            es_model = CreatLocalIndex()
            es_model.createLocalIndex(order_number)
            if len(selffileList) > 0:
                for item in selffileList:
                    insertSelfDababase(item, order_number)
                    sleep(2)
            if checkmodel == 2:
                target_redisclient.hset_task(order_number)
                if queue == 'high':
                    target_redisclient.push_task(LOCAL_TASK, order_number)
                    target_redisclient.push_task(PRE_INTERNET_TASK, order_number)
                else:
                    target_redisclient.push_task('pre_local_task', order_number)
                check_part = ''
                for item in parseModel.contents:
                    if item['check'] == 1:
                        check_part += item['content']
                        if len(check_part) > 1000:
                            try:
                                keywords = get_key_words(check_part)
                                target_redisclient.client.rpush(f'{KEYWORDS_INTERNET}{order_number}', keywords)
                            except Exception as e:
                                print(order_number, str(e))
                            check_part = ''
                try:
                    keywords = get_key_words(check_part)
                    target_redisclient.client.rpush(f'{KEYWORDS_INTERNET}{order_number}', keywords)
                except Exception as e:
                    print(order_number, str(e))
            else:
                target_redisclient.push_task(LAST_TASK, order_number)
        print('save data complete!')


def __db_document_operation_sync(file_path, order_number, selffileList, checkmodel):
        try:
            with db.auto_commit():
                parseDocument(file_path, order_number)

                Document = ParseDocumentHtml(order_number)
                Document.parseDom()
                documentDoms = DocumentDom()
                documentDoms.insert_doms(Document.domModel)

                paragraphs = DocumentDom.query.filter_by(order_number=order_number).filter_by(paragraph=1).all()

                parseModel = ParseDocument(paragraphs)
                parseModel.cut()
                sentenceWordModel = SentenceWord()
                sentenceWordModel.insert_sentences(parseModel.contents, order_number)
                target_redisclient = redisclientRemote
                es_model = CreatLocalIndex()
                check_sentences = SentenceWord.query.filter_by(order_number=order_number).filter_by(check=1).order_by(
                    SentenceWord.check_id).all()
                target_redisclient.setCheckData(check_sentences, checkmodel, selffileList)
                es_model.createLocalIndex(order_number)
                target_redisclient.hset_task(order_number)
                if len(selffileList) > 0:
                    for item in selffileList:
                        insertSelfDababase(item, order_number)
                        sleep(10)
                if checkmodel == 2:
                    target_redisclient.hset_task(order_number)
                    target_redisclient.push_task(LOCAL_TASK, order_number)
                    target_redisclient.push_task(PRE_INTERNET_TASK, order_number)
                else:
                    target_redisclient.push_task(LAST_TASK, order_number)
        except Exception as e:
            print(e)
            traceback.print_exc()

def __db_document_operation(file_path, order_number, selffileList, checkmodel,queue, app):
    with app.app_context():
        try:
            with db.auto_commit():
                parseDocument(file_path, order_number)

                Document = ParseDocumentHtml(order_number)
                Document.parseDom()
                documentDoms = DocumentDom()
                documentDoms.insert_doms(Document.domModel)

                paragraphs = DocumentDom.query.filter_by(order_number=order_number).filter_by(paragraph=1).all()

                parseModel = ParseDocument(paragraphs)
                parseModel.cut()
                sentenceWordModel = SentenceWord()
                sentenceWordModel.insert_sentences(parseModel.contents, order_number)
                target_redisclient = redisclientRemote
                es_model = CreatLocalIndex()
                check_sentences = SentenceWord.query.filter_by(order_number=order_number).filter_by(check=1).order_by(
                    SentenceWord.check_id).all()
                target_redisclient.setCheckData(check_sentences, checkmodel, selffileList)
                es_model.createLocalIndex(order_number)
                target_redisclient.hset_task(order_number)
                if len(selffileList) > 0:
                    for item in selffileList:
                        insertSelfDababase(item, order_number)
                        sleep(10)
                if checkmodel == 2:
                    target_redisclient.hset_task(order_number)
                    if queue == 'high':
                        target_redisclient.push_task(LOCAL_TASK, order_number)
                        target_redisclient.push_task(PRE_INTERNET_TASK, order_number)
                    else:
                        target_redisclient.push_task('pre_local_task', order_number)
                    check_part = ''
                    for item in check_sentences:
                        if item['check'] == 1:
                            check_part += item.content
                            if len(check_part) > 1000:
                                try:
                                    keywords = get_key_words(check_part)
                                    target_redisclient.client.rpush(f'{KEYWORDS_INTERNET}{order_number}', keywords)
                                except Exception as e:
                                    print(order_number, str(e))
                                check_part = ''
                    try:
                        keywords = get_key_words(check_part)
                        target_redisclient.client.rpush(f'{KEYWORDS_INTERNET}{order_number}', keywords)
                    except Exception as e:
                        print(order_number, str(e))
                else:
                    target_redisclient.push_task(LAST_TASK, order_number)
        except Exception as e:
            print(e)
            traceback.print_exc()


def insertSelfDababase(file, order_number):
    title = file.split(SELFDOC_PATH)[1]
    data = {
        "title": title,
        "path": file,
        "author": '自建库',
        "periodical": '自建库',
        "database": 'last_' + order_number
    }
    requests.post(InsertDocUrl, verify=False, json=data)


def __writer_db_operation(order_number, content, app):
    with app.app_context():
        with db.auto_commit():
            parseModel = ParseArticle(content)
            parseModel.cut()
            paragraph_model = Paragraphs()
            sentence_model = sentence()
            target_redisclient = redisclientRemote
            paragraph_model.insert_paragrahs(parseModel.paragraph_content, order_number)
            sentence_model.insert_sentences(parseModel.contents, order_number)
            es_model = CreatLocalIndex()
            check_sentences = sentence.query.filter_by(order_number=order_number).filter_by(check=1).order_by(
                sentence.check_id).all()
            target_redisclient.setCheckData(check_sentences,checkmodel=2,selffileList=[])
            es_model.createLocalIndex(order_number)
            target_redisclient.hset_task(order_number)
            check_part = ''
            for item in check_sentences:
                if item['check'] == 1:
                    check_part += item['content']
                    if len(check_part) > 1000:
                        keywords = get_key_words(check_part)
                        target_redisclient.client.rpush(f'{KEYWORDS_INTERNET}{order_number}', keywords)
                        check_part = ''
            target_redisclient.push_task(PRE_INTERNET_TASK, order_number)
            target_redisclient.push_task(LOCAL_TASK, order_number)


@api.route('/test', methods=['GET'])
def test():
    bot = PosterGenerator()
    bot.unlockAIGCPoster()
    return Success()